package com.gateway.filters;

import com.commons.utils.Constance;
import com.gateway.exceptions.IllegalTokenException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

/**
 * 自定义局部过滤器
 * 做用户认证,使用token
 * @author mis_wu
 * @date 2021/12/4 23:24
 * 使用配置中添加 filters -Token （TokenGatewayFilterFactory XXXXGatewayFilterFactory）
 * 参照 StripPrefix
 */
@Component
public class TokenGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenGatewayFilterFactory.Config> {

    private static final Logger log=LoggerFactory.getLogger(TokenGatewayFilterFactory.class);

    private static final String REQUEST_TOKEN = "token";

    @Resource
    private RedisTemplate redisTemplate;

    public TokenGatewayFilterFactory(){
        super(Config.class);
    }

    /**
     *
     * Config参数就是基于当前的类中的Config配置类创建对象
     */
    @Override
    public GatewayFilter apply(Config config) {
        // servlet service(httpservletRequest,httpservletResponse) 传统web
        // springmvc springwebflux new web模型
        // filter request,response,filterChain.dofilter(request,response)
        return new GatewayFilter() {
            //exchange 交换机
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                log.info(">>> 进入filter过滤器 >>>");
                log.info("requiredToken: {}, author: {}",config.requiredToken,config.author);
                //可以给application.properties中的 - Token赋值 若为true则验证  false则不验证
                if (config.requiredToken){
                    //1、获取请求头token信息
                    List<String> requests = exchange.getRequest().getQueryParams().get(REQUEST_TOKEN);
                    if (ObjectUtils.isEmpty(requests)){
                        throw new IllegalTokenException("非法令牌");
                    }
                    String token = requests.get(0);
                    log.info("token信息:{}"+token);
                    //2、根据token去redis获取
                    if (Boolean.FALSE.equals(redisTemplate.hasKey(Constance.TOKEN_KEY + token))) {
                        throw new IllegalTokenException("不合法的令牌");
                    }
                }
                return chain.filter(exchange);
            }
        };
    }

    /**
     * 用来配置filter时指定值 赋值给 Config中的哪个属性
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        //指定传参的顺序
        return Arrays.asList("requiredToken","author");
    }


    /**
     * 静态内部类 自定义配置类  可以传多个属性
     */
    public static class Config{
        private boolean requiredToken; //false
        private String author;

        public String getAuthor() {
            return author;
        }

        public void setAuthor(String author) {
            this.author = author;
        }

        public boolean isRequiredToken() {
            return requiredToken;
        }

        public void setRequiredToken(boolean requiredToken) {
            this.requiredToken = requiredToken;
        }
    }
}
